home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / -archivi / -recent2 / amhelios.lha / AmHelios / syn_cam.cpp < prev    next >
C/C++ Source or Header  |  1997-08-24  |  18KB  |  701 lines

  1. ////////////////////////////////////////////////////////////
  2. //
  3. //  SYN_CAM.CPP - Synthetic Camera Class
  4. //
  5. //  Version:    1.03A
  6. //
  7. //  History:    94/08/23 - Version 1.00A release.
  8. //              94/11/26 - Modified Preview and Shoot
  9. //                         functions.
  10. //              94/12/16 - Version 1.01A release.
  11. //              95/02/05 - Version 1.02A release.
  12. //              95/03/21 - Added antialiasing support to
  13. //                         Shoot function.
  14. //                       - Added OpenBuffer, CloseBuffer,
  15. //                         InstBartlettFilter, GetMaxPass,
  16. //                         GetNumFilters and RenderPolygons
  17. //                         functions.
  18. //                       - Added BartlettParam array.
  19. //              95/03/25 - Added gamma correction and color
  20. //                         reduction to Shoot function.
  21. //              95/06/17 - Added color conversion logic to
  22. //                         Shoot function.
  23. //              95/06/28 - Added Reset function.
  24. //              95/07/21 - Version 1.02B release.
  25. //              95/10/11 - Modified WinMeta::Record function
  26. //                         call.
  27. //              96/02/14 - Version 1.02C release.
  28. //              96/02/21 - Added Abort function.
  29. //              96/03/30 - Deleted SetViewDirVector and
  30. //                         SetViewUpVector functions.
  31. //                       - Deleted "spheric3.h" include
  32. //                         directive.
  33. //              96/04/01 - Version 1.03A release.
  34. //
  35. //  Compilers:  Microsoft Visual C/C++ Professional V1.5
  36. //              Borland C++ Version 4.5
  37. //
  38. //  Author:     Ian Ashdown, P.Eng.
  39. //              byHeart Software Limited
  40. //              620 Ballantree Road
  41. //              West Vancouver, B.C.
  42. //              Canada V7S 1W3
  43. //              Tel. (604) 922-6148
  44. //              Fax. (604) 987-7621
  45. //
  46. //  Copyright 1994-1996 byHeart Software Limited
  47. //
  48. //  The following source code has been derived from:
  49. //
  50. //    Ashdown, I. 1994. Radiosity: A Programmer's
  51. //    Perspective. New York, NY: John Wiley & Sons.
  52. //
  53. //  It may be freely copied, redistributed, and/or modified
  54. //  for personal use ONLY, as long as the copyright notice
  55. //  is included with all source code files.
  56. //
  57. ////////////////////////////////////////////////////////////
  58.  
  59. #include "syn_cam.h"
  60.  
  61. // Static Bartlett filter parameters array
  62. BartParam SynCamera::BartlettParam[] =
  63. {
  64.   { 0.0000, 1, "None", "None" },
  65.   { 0.5000, 3, "3 x 3", "3 x 3 Bartlett" },
  66.   { 0.3333, 5, "5 x 5", "5 x 5 Bartlett" },
  67.   { 0.2500, 7, "7 x 7", "7 x 7 Bartlett" }
  68. };
  69.  
  70. // Record wireframe display in metafile format
  71. BOOL SynCamera::Preview( Environ *penv, WinMetaFile
  72.     *pmeta )
  73. {
  74.   int i;                // Loop index
  75.   int num_vert;         // Number of vertices
  76.   Element3 *pelem;      // Element pointer
  77.   Instance *pinst;      // Instance pointer
  78.   OutPolygon out;       // Output polygon
  79.   POINT vertex[8];      // Polygon vertex array
  80.   Point3 posn;          // Point co-ordinates
  81.   Patch3 *ppatch;       // Patch pointer
  82.   Surface3 *psurf;      // Surface pointer
  83.  
  84.   // Start wireframe metafile recording
  85.   if (pmeta->Record(TRUE) == FALSE)
  86.     return FALSE;
  87.  
  88.   // Walk the instance list
  89.   pinst = penv->GetInstPtr();
  90.   while (pinst != NULL)
  91.   {
  92.     // Walk the surface list
  93.     psurf = pinst->GetSurfPtr();
  94.     while (psurf != NULL)
  95.     {
  96.       // Walk the patch list
  97.       ppatch = psurf->GetPatchPtr();
  98.       while (ppatch != NULL)
  99.       {
  100.         // Determine patch visibility
  101.         if (BackFaceCull(ppatch) == FALSE)
  102.         {
  103.           // Walk the element list
  104.           pelem = ppatch->GetElementPtr();
  105.           while (pelem != NULL)
  106.           {
  107.             // Clip the 3-D element (polygon)
  108.             num_vert = clipper.Clip(pelem, out,
  109.                 GetProjMatrix());
  110.  
  111.             // Initialize the 2-D polygon vertices array
  112.             for (i = 0; i < num_vert; i++)
  113.             {
  114.               posn  = out.GetVertexPosn(i);
  115.  
  116.               // Convert normalized device co-ordinates to
  117.               // screen space co-ordinates
  118.               vertex[i].x = (int) (posn.GetX() * width);
  119.               vertex[i].y = (int) (posn.GetY() * height);
  120.             }
  121.  
  122.             // Add 2-D polygon draw command to metafile
  123.             if (pmeta->Polygon(vertex, num_vert) == FALSE)
  124.             {
  125.               pmeta->Erase();   // Erase metafile recording
  126.               return FALSE;
  127.             }
  128.  
  129.             pelem = pelem->GetNext();
  130.           }
  131.         }
  132.         ppatch = ppatch->GetNext();
  133.       }
  134.       psurf = psurf->GetNext();
  135.     }
  136.     pinst = pinst->GetNext();
  137.   }
  138.   return pmeta->Stop();         // Stop metafile recording
  139. }
  140.  
  141. // Record wireframe display in metafile format, only using box outline
  142. BOOL SynCamera::BoxPreview( Environ *penv, WinMetaFile *pmeta, int level)
  143. {
  144.     Vertex3 *vrtx[4];
  145.     Point3 pnt;
  146.     Element3 *pelem;
  147.     int wx[4][4] = { { 0, 1, 1, 0 }, { 0, 1, 1, 0}, {0, 1, 1, 0}, {0, 1, 1, 0} };
  148.     int wy[4][4] = { { 1, 1, 0, 0 }, { 1, 1, 1, 1}, {0, 0, 1, 1}, {0, 0, 0, 0} };
  149.     int wz[4][4] = { { 0, 0, 0, 0 }, { 1, 1, 0, 0}, {1, 1, 1, 1}, {0, 0, 1, 1} };
  150.     double x[2],y[2],z[2];
  151.     int t,s,u,v;
  152.     BOOL probs;
  153.     Instance *pinst;
  154.     double mx,my,mz;
  155.     Vector3 tv;
  156.  
  157.     probs = FALSE;
  158.  
  159.     // Start wireframe metafile recording
  160.     if (pmeta->Record(TRUE) == FALSE)
  161.         return FALSE;
  162.  
  163.     x[0] = penv->GetMin_X();
  164.     y[0] = penv->GetMin_Y();
  165.     z[0] = penv->GetMin_Z();
  166.     x[1] = penv->GetMax_X();
  167.     y[1] = penv->GetMax_Y();
  168.     z[1] = penv->GetMax_Z();
  169.  
  170.     for(t=0; t<4; t++)
  171.         vrtx[t] = new Vertex3(pnt);
  172.  
  173.     pelem = new Element3(vrtx,NULL);
  174.     pelem->SetQuad();
  175.  
  176.     // Grid
  177.     //
  178.     pmeta->SetColor(FILLPEN);
  179.     for(u=-3; u<3; u++)
  180.     {
  181.         for(v=-3; v<3; v++)
  182.         {
  183.             for(t=0; t<4; t++)
  184.             {
  185.                 pnt.SetX(x[wx[0][t]]+u*(x[1]-x[0]));
  186.                 pnt.SetY(y[wy[0][t]]+v*(y[1]-y[0]));
  187.                 pnt.SetZ(z[wz[0][t]]);
  188.  
  189.                 vrtx[t]->SetPosn(pnt);
  190.             }
  191.             if(BoxPreviewElem(penv, pelem, pmeta) == FALSE)
  192.             {
  193.                 probs = TRUE;
  194.                 goto error;
  195.             }
  196.         }
  197.     }
  198.  
  199.     if(level == 0)
  200.     {
  201.         // Box outline
  202.         //
  203.         pmeta->SetColor(TEXTPEN);
  204.         for(s=0; s<4; s++)
  205.         {
  206.             for(t=0; t<4; t++)
  207.             {
  208.                 pnt.SetX(x[wx[s][t]]);
  209.                 pnt.SetY(y[wy[s][t]]);
  210.                 pnt.SetZ(z[wz[s][t]]);
  211.  
  212.                 vrtx[t]->SetPosn(pnt);
  213.             }
  214.  
  215.             // Add 2-D polygon draw command to metafile
  216.             if(BoxPreviewElem(penv, pelem, pmeta) == FALSE)
  217.             {
  218.                 probs = TRUE;
  219.                 goto error;
  220.             }
  221.         }
  222.     }
  223.     else if(level == 1)
  224.     {
  225.         // Box outline using instance boxes
  226.         //
  227.         pmeta->SetColor(TEXTPEN);
  228.         pinst = penv->GetInstPtr();
  229.         while(pinst != NULL)
  230.         {
  231.             x[0] = pinst->GetMin_X();
  232.             y[0] = pinst->GetMin_Y();
  233.             z[0] = pinst->GetMin_Z();
  234.             x[1] = pinst->GetMax_X();
  235.             y[1] = pinst->GetMax_Y();
  236.             z[1] = pinst->GetMax_Z();
  237.  
  238.             for(s=0; s<4; s++)
  239.             {
  240.                 for(t=0; t<4; t++)
  241.                 {
  242.                     pnt.SetX(x[wx[s][t]]);
  243.                     pnt.SetY(y[wy[s][t]]);
  244.                     pnt.SetZ(z[wz[s][t]]);
  245.  
  246.                     vrtx[t]->SetPosn(pnt);
  247.                 }
  248.  
  249.                 // Add 2-D polygon draw command to metafile
  250.                 if(BoxPreviewElem(penv, pelem, pmeta) == FALSE)
  251.                 {
  252.                     probs = TRUE;
  253.                     goto error;
  254.                 }
  255.             }
  256.  
  257.             pinst = pinst->GetNext();
  258.         }
  259.     }
  260.     else if(level == 2)
  261.     {
  262.         if(Preview(penv,pmeta) == FALSE)
  263.         {
  264.             probs = TRUE;
  265.             goto error;
  266.         }
  267.     }
  268.  
  269.     // Focus position
  270.     //
  271.     pmeta->SetColor(SHINEPEN);
  272.     mx = penv->GetMax_X()-penv->GetMin_X();
  273.     my = penv->GetMax_Y()-penv->GetMin_Y();
  274.     mz = penv->GetMax_Z()-penv->GetMin_Z();
  275.     tv = GetLRVector()*(min(min(mx,my),mz))/10.0;
  276.     pnt = GetFocusPosn();
  277.     pnt.SetZ(0.0);
  278.     pnt = pnt + (-tv);
  279.     vrtx[0]->SetPosn(pnt);
  280.     pnt = pnt + tv;
  281.     vrtx[1]->SetPosn(pnt);
  282.     pnt = pnt + tv;
  283.     vrtx[2]->SetPosn(pnt);
  284.     pnt = GetFocusPosn();
  285.     vrtx[3]->SetPosn(pnt);
  286.     if(BoxPreviewElem(penv, pelem, pmeta) == FALSE)
  287.     {
  288.         probs = TRUE;
  289.         goto error;
  290.     }
  291.  
  292. error:
  293.     for(t=0; t<4; t++)
  294.         delete vrtx[t];
  295.     delete pelem;
  296.  
  297.     if(!probs)
  298.         return pmeta->Stop();         // Stop metafile recording
  299.  
  300.     pmeta->Erase();
  301.     return FALSE;
  302. }
  303.  
  304. BOOL SynCamera::BoxPreviewElem( Environ *penv, Element3 *pelem, WinMetaFile *pmeta)
  305. {
  306.     int i;                // Loop index
  307.     int num_vert;         // Number of vertices
  308.     OutPolygon out;       // Output polygon
  309.     POINT vertex[8];      // Polygon vertex array
  310.     Point3 posn;          // Point co-ordinates
  311.  
  312.     // Clip the 3-D element (polygon)
  313.     num_vert = clipper.Clip(pelem, out,GetProjMatrix());
  314.  
  315.     // Initialize the 2-D polygon vertices array
  316.     for (i = 0; i < num_vert; i++)
  317.     {
  318.         posn  = out.GetVertexPosn(i);
  319.  
  320.         // Convert normalized device co-ordinates to
  321.         // screen space co-ordinates
  322.         vertex[i].x = (int) (posn.GetX() * width);
  323.         vertex[i].y = (int) (posn.GetY() * height);
  324.     }
  325.  
  326.     // Add 2-D polygon draw command to metafile
  327.     return pmeta->Polygon(vertex, num_vert);
  328. }
  329.  
  330.  
  331. // Record rendered display as bitmap file
  332. BOOL SynCamera::Shoot( Environ *penv, WinBitmap *pbmap, BOOL
  333.     *pmore )
  334. {
  335.   int row;              // Row index
  336.   int col;              // Column index
  337.   WORD alpha;           // Subpixel blend coeff
  338.   WORD beta;            // Pixel blend coefficient
  339.   ColorRGB *ppixel;     // Pixel pointer
  340.   ColorRGB new_rgb;     // New pixel color
  341.  
  342.   // Initialize polygon renderer
  343.   if (fp_flag == TRUE)
  344.   {
  345.     if (renderer.Open(pbmap, penv->GetMaxReflect()) == FALSE)
  346.       return FALSE;
  347.   }
  348.  
  349.   if (ss_res != SC_None)    // Antialiasing required ?
  350.   {
  351.     if (fp_flag == TRUE)
  352.     {
  353.       // Open antialiasing buffer
  354.       if (OpenBuffer(pbmap) == TRUE)
  355.         fp_flag = FALSE;
  356.       else
  357.       {
  358.         // Close the polygon renderer
  359.         renderer.Close();
  360.  
  361.         return FALSE;
  362.       }
  363.     }
  364.  
  365.     // Get Bartlett filter blending info
  366.     alpha = (WORD) pbart[pass].alpha;
  367.     beta = (WORD) pbart[pass].beta;
  368.  
  369.     // Render subpixel bitmap
  370.     RenderPolygons(penv, BartlettParam[ss_res].width,
  371.         pbart[pass].x_offset, pbart[pass].y_offset);
  372.  
  373.     // Blend bitmaps
  374.     for (row = 0; row < height; row++)
  375.     {
  376.       for (col = 0; col < width; col++)
  377.       {
  378.         // Get new subpixel value
  379.         pbmap->GetPixel(col, row, &new_rgb);
  380.  
  381.         // Get current pixel value
  382.         ppixel = &(pabuf[row][col]);
  383.  
  384.         // Blend pixel and subpixel values
  385.         ppixel->SetRed((BYTE) (((WORD) new_rgb.GetRed() *
  386.             alpha + (WORD) ppixel->GetRed() * beta) /
  387.             256));
  388.         ppixel->SetGreen((BYTE) (((WORD) new_rgb.GetGreen()
  389.             * alpha + (WORD) ppixel->GetGreen() * beta) /
  390.             256));
  391.         ppixel->SetBlue((BYTE) (((WORD) new_rgb.GetBlue()
  392.             * alpha + (WORD) ppixel->GetBlue() * beta) /
  393.             256));
  394.       }
  395.     }
  396.  
  397.     renderer.Reset();       // Clear the subpixel bitmap
  398.     pass++;                 // Increment the pass count
  399.  
  400.     if (pass < num_sub)     // More passes needed ?
  401.     {
  402.       *pmore = TRUE;
  403.       return TRUE;
  404.     }
  405.  
  406.     // Copy antialiasing buffer to bitmap
  407.     for (row = 0; row < height; row++)
  408.       for (col = 0; col < width; col++)
  409.         pbmap->SetPixel(col, row, pabuf[row][col]);
  410.  
  411.     CloseBuffer();      // Close the antialiasing buffer
  412.   }
  413.   else
  414.   {
  415.     // Render bitmap (no antialiasing)
  416.     RenderPolygons(penv, 1, 0.0, 0.0);
  417.   }
  418.  
  419.   renderer.Close();     // Close the polygon renderer
  420.  
  421.   for (row = 0; row < height; row++)
  422.     for (col = 0; col < width; col++)
  423.     {
  424.       // Get the bitmap pixel
  425.       pbmap->GetPixel(col, row, &new_rgb);
  426.  
  427.       switch (color_type)
  428.       {
  429.         case SC_MONO:           // Convert to grayscale
  430.           new_rgb.SetMono();
  431.           break;
  432.         case SC_PSEUDO:         // Convert to pseudocolor
  433.           new_rgb.SetPseudo();
  434.           break;
  435.         default:
  436.           break;
  437.       }
  438.  
  439.       if (gamma_flag == TRUE)
  440.       {
  441.         // Perform gamma correction
  442.         gamma.Correct(new_rgb);
  443.       }
  444.  
  445.       if (jitter_flag == TRUE)
  446.       {
  447.         // Perform color reduction
  448.         jitter.Reduce(&new_rgb, col, row);
  449.       }
  450.  
  451.       // Set bitmap pixel
  452.       pbmap->SetPixel(col, row, new_rgb);
  453.     }
  454.  
  455.   pass = 0;         // Reset number of passes
  456.   fp_flag = TRUE;   // Reset first pass flag
  457.   *pmore = FALSE;   // Indicate completion
  458.  
  459.   return TRUE;
  460. }
  461.  
  462. // Abort rendering
  463. void SynCamera::Abort()
  464. {
  465.   CloseBuffer();        // Close the antialiasing buffer
  466.   renderer.Close();     // Close the polygon renderer
  467.   Reset();              // Reset the camera
  468. }
  469.  
  470. // Reset camera
  471. void SynCamera::Reset()
  472. {
  473.   pass = 0;
  474.   fp_flag = TRUE;
  475. }
  476.  
  477. // Set view system parameters
  478. void SynCamera::UpdateViewSystem()
  479. {
  480.   aspect = (double) width / (double) height;
  481.   BuildTransform();
  482. }
  483.  
  484. // Get maximum number of passes
  485. int SynCamera::GetMaxPass()
  486. {
  487.   int width;    // Array width
  488.  
  489.   width = BartlettParam[ss_res].width;
  490.   return width * width;
  491. }
  492.  
  493. // Get current antialiasing filter name
  494. char *SynCamera::GetCurrFilterName()
  495. {
  496.   return BartlettParam[ss_res].pname;
  497. }
  498.  
  499. // Get current antialiasing filter name
  500. char *SynCamera::GetCurrFilterSize()
  501. {
  502.   return BartlettParam[ss_res].psize;
  503. }
  504.  
  505. // Get antialiasing filter name
  506. char *SynCamera::GetFilterSize( int i )
  507. {
  508.   return BartlettParam[i].psize;
  509. }
  510.  
  511. // Get number of antialiasing filters
  512. int SynCamera::GetNumFilters()
  513. {
  514.   return (sizeof(BartlettParam) / sizeof(BartParam));
  515. }
  516.  
  517. // Open antialiasing buffer
  518. BOOL SynCamera::OpenBuffer( WinBitmap *pbmap )
  519. {
  520.   int row, col;         // Loop indices
  521.   ColorRGB *ppixel;     // Pixel pointer
  522.  
  523.   // Get bitmap dimensions
  524.   height = pbmap->GetHeight();
  525.   width = pbmap->GetWidth();
  526.  
  527.   // Instantiate Bartlett filter
  528.   if (InstBartlettFilter() == FALSE)
  529.     return FALSE;
  530.  
  531.   // Allocate subpixel bitmap buffer
  532.   if ((pabuf = new (ColorRGB (*[height]))) != NULL)
  533.   {
  534.     for (row = 0; row < height; row++)
  535.     {
  536.       if ((pabuf[row] = new ColorRGB[width]) == NULL)
  537.       {
  538.         // Release partially allocated buffer
  539.         row--;
  540.         for ( ; row >= 0; row--)
  541.           delete [] pabuf[row];
  542.         delete [] pabuf;
  543.  
  544.         delete [] pbart;    // Release Bartlett filter
  545.         return FALSE;
  546.       }
  547.     }
  548.  
  549.     // Clear antialiasing buffer
  550.     for (row = 0; row < height; row++)
  551.       for (col = 0; col < width; col++)
  552.       {
  553.         ppixel = &(pabuf[row][col]);
  554.  
  555.         ppixel->SetRed((BYTE) 0);
  556.         ppixel->SetGreen((BYTE) 0);
  557.         ppixel->SetBlue((BYTE) 0);
  558.       }
  559.  
  560.     return TRUE;
  561.   }
  562.   else
  563.   {
  564.     delete [] pbart;    // Release Bartlett filter
  565.     return FALSE;
  566.   }
  567. }
  568.  
  569. // Close antialiasing buffer
  570. void SynCamera::CloseBuffer()
  571. {
  572.   int row;  // Loop index
  573.  
  574.   delete [] pbart;  // Release Bartlett filter
  575.  
  576.   // Release subpixel bitmap buffer
  577.   for (row = 0; row < height; row++)
  578.     delete [] pabuf[row];
  579.   delete [] pabuf;
  580. }
  581.  
  582. // Render polygons
  583. void SynCamera::RenderPolygons( Environ *penv, int width,
  584.     double x_offset, double y_offset )
  585. {
  586.   Element3 *pelem;      // Element pointer
  587.   Instance *pinst;      // Instance pointer
  588.   OutPolygon out;       // Output polygon
  589.   Patch3 *ppatch;       // Patch pointer
  590.   Surface3 *psurf;      // Surface pointer
  591.  
  592.   // Walk the instance list
  593.   pinst = penv->GetInstPtr();
  594.   while (pinst != NULL)
  595.   {
  596.     // Walk the surface list
  597.     psurf = pinst->GetSurfPtr();
  598.     while (psurf != NULL)
  599.     {
  600.       // Walk the patch list
  601.       ppatch = psurf->GetPatchPtr();
  602.       while (ppatch != NULL)
  603.       {
  604.         // Determine patch visibility
  605.         if (BackFaceCull(ppatch) == FALSE)
  606.         {
  607.           // Walk the element list
  608.           pelem = ppatch->GetElementPtr();
  609.           while (pelem != NULL)
  610.           {
  611.             // Clip the 3-D polygon
  612.             (void) clipper.Clip(pelem, out,
  613.                 GetProjMatrix());
  614.  
  615.             // Render the 2-D polygon
  616.             renderer.Render(out, width, x_offset, y_offset);
  617.  
  618.             pelem = pelem->GetNext();
  619.           }
  620.         }
  621.         ppatch = ppatch->GetNext();
  622.       }
  623.       psurf = psurf->GetNext();
  624.     }
  625.     pinst = pinst->GetNext();
  626.   }
  627. }
  628.  
  629. // Instantiate Bartlett filter
  630. BOOL SynCamera::InstBartlettFilter()
  631. {
  632.   int i, j, m, n;       // Loop indices
  633.   int sum = 0;          // Sum of previous subpixel weights
  634.   int array_width;      // Array width
  635.   double offset;        // Subpixel offset
  636.   Bartlett *pbfe;       // Bartlett filter element pointer
  637.   Bartlett *psbfe;      // Second filter element pointer
  638.  
  639.   // Get Bartlett filter parameters
  640.   offset = BartlettParam[ss_res].offset;
  641.   array_width = BartlettParam[ss_res].width;
  642.  
  643.   // Allocate blending info array
  644.   num_sub = array_width * array_width;
  645.   if ((pbart = new Bartlett[num_sub]) == NULL)
  646.     return FALSE;
  647.  
  648.   // Calculate offsets and weights
  649.   for (i = 0; i <= array_width / 2; i++)
  650.   {
  651.     m = array_width - i - 1;
  652.     {
  653.       for (j = 0; j <= array_width / 2; j++)
  654.       {
  655.         n = array_width - j - 1;
  656.         pbfe = &(pbart[i * array_width + j]);
  657.  
  658.         pbfe->x_offset = (offset * (double) (j + 1) - 1.0);
  659.         pbfe->y_offset = 1.0 - (offset * (double) (i + 1));
  660.         pbfe->weight = (i + 1) * (j + 1);
  661.  
  662.         if (j != n)
  663.         {
  664.           psbfe = &(pbart[i * array_width + n]);
  665.           psbfe->x_offset = -pbfe->x_offset;
  666.           psbfe->y_offset = pbfe->y_offset;
  667.           psbfe->weight = pbfe->weight;
  668.         }
  669.  
  670.         if (i != m)
  671.         {
  672.           psbfe = &(pbart[m * array_width + j]);
  673.           psbfe->x_offset = pbfe->x_offset;
  674.           psbfe->y_offset = -pbfe->y_offset;
  675.           psbfe->weight = pbfe->weight;
  676.  
  677.           if (j != n)
  678.           {
  679.             psbfe = &(pbart[m * array_width + n]);
  680.             psbfe->x_offset = -pbfe->x_offset;
  681.             psbfe->y_offset = -pbfe->y_offset;
  682.             psbfe->weight = pbfe->weight;
  683.           }
  684.         }
  685.       }
  686.     }
  687.   }
  688.  
  689.   // Calculate blending info
  690.   for (i = 0; i < num_sub; i++)
  691.   {
  692.     pbfe = &(pbart[i]);
  693.     sum += pbfe->weight;
  694.     pbfe->alpha = (pbfe->weight * 256) / sum;
  695.     pbfe->beta = 256 - pbfe->alpha;
  696.   }
  697.  
  698.   return TRUE;
  699. }
  700.  
  701.